/* Inform cairo we altered the surfaces contents. */
cairo_surface_mark_dirty (surface);
}
+
+/**
+ * _gtk_cairo_blur_compute_pixels:
+ * @radius: the radius to compute the pixels for
+ *
+ * Computes the number of pixels necessary to extend an image in one
+ * direction to hold the image with shadow.
+ *
+ * This is just the number of pixels added by the blur radius, shadow
+ * offset and spread are not included.
+ *
+ * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
+ * approximating a Gaussian using box blurs. This yields quite a good
+ * approximation for a Gaussian. Then we multiply this by 1.5 since our
+ * code wants the radius of the entire triple-box-blur kernel instead of
+ * the diameter of an individual box blur. For more details, see:
+ * http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
+ */
+#define GAUSSIAN_SCALE_FACTOR ((3.0 * sqrt(2 * G_PI) / 4) * 1.5)
+
+int
+_gtk_cairo_blur_compute_pixels (double radius)
+{
+ return floor (radius * GAUSSIAN_SCALE_FACTOR + 0.5);
+}
G_BEGIN_DECLS
-void _gtk_cairo_blur_surface (cairo_surface_t *surface,
- double radius);
+void _gtk_cairo_blur_surface (cairo_surface_t *surface,
+ double radius);
+int _gtk_cairo_blur_compute_pixels (double radius);
G_END_DECLS
#include "gtkcssshadowsvalueprivate.h"
+#include "gtkcairoblurprivate.h"
#include "gtkcssshadowvalueprivate.h"
#include <string.h>
guint i;
GtkBorder b = { 0 };
const GtkCssValue *shadow;
- gdouble hoffset, voffset, spread, radius;
+ gdouble hoffset, voffset, spread, radius, clip_radius;
g_return_if_fail (shadows->class == >K_CSS_VALUE_SHADOWS);
_gtk_css_shadow_value_get_geometry (shadow,
&hoffset, &voffset,
&radius, &spread);
+ clip_radius = _gtk_cairo_blur_compute_pixels (radius);
- b.top = MAX (0, radius + spread - voffset);
- b.right = MAX (0, radius + spread + hoffset);
- b.bottom = MAX (0, radius + spread + voffset);
- b.left = MAX (0, radius + spread - hoffset);
+ b.top = MAX (0, clip_radius + spread - voffset);
+ b.right = MAX (0, clip_radius + spread + hoffset);
+ b.bottom = MAX (0, clip_radius + spread + voffset);
+ b.left = MAX (0, clip_radius + spread - hoffset);
border->top = MAX (border->top, b.top);
border->right = MAX (border->right, b.right);
#include <math.h>
-/* The blur of _gtk_cairo_blur_surface only approximately ends at radius,
- so we add an extra pixel to make the clips less dramatic */
-#define CLIP_RADIUS_EXTRA 4
-
struct _GtkCssValue {
GTK_CSS_VALUE_BASE
guint inset :1;
gdk_cairo_get_clip_rectangle (cr, &clip_rect);
- clip_radius = radius + CLIP_RADIUS_EXTRA;
+ clip_radius = _gtk_cairo_blur_compute_pixels (radius);
/* Create a larger surface to center the blur. */
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
spread = _gtk_css_number_value_get (shadow->spread, 0);
radius = _gtk_css_number_value_get (shadow->radius, 0);
- clip_radius = radius + CLIP_RADIUS_EXTRA;
+ clip_radius = _gtk_cairo_blur_compute_pixels (radius);
x = _gtk_css_number_value_get (shadow->hoffset, 0);
y = _gtk_css_number_value_get (shadow->voffset, 0);